<template>
  <div class="my-contextmenu"
       v-show="visible"
       :class="classes"
       :style="styles">
    <Menu v-if="visible" ref="menu" :items="data"></Menu>
  </div>
</template>

<script>
/**
 * 右键菜单组件
 * @module $ui/components/my-contextmenu
 */
import {on, off} from 'element-ui/lib/utils/dom'
import Menu from './Menu'

/**
 * 点击菜单项时触发
 * @event click
 * @param {Object} item 菜单项数据
 * @param {Object} vm 菜单项实例
 */

export default {
  name: 'MyContextmenu',
  components: {
    Menu
  },
  provide() {
    return {
      wrapper: this
    }
  },
  /**
   * 属性参数
   * @member props
   * @property {string} [theme=light] 主题配色，可选 'light', 'dark'
   * @property {Array} [data] 菜单项数据，[{icon, label, info, disabled, divider, children}]
   * @property {string|object} [data.icon] 图标
   * @property {string} [data.label] 标题文本
   * @property {string} [data.info] 附加信息文本
   * @property {boolean} [data.disabled] 禁用
   * @property {boolean} [data.divider] 分割线
   * @property {Array} [data.children] 子菜单项
   * @property {boolean} [disabled] 禁用菜单
   * @property {number} [zIndex=1000] 显示层级
   * @property {String|HTMLElement|Function} 触发菜单容器，支持选择器和函数，默认 document.body
   * @property {boolean} [manual] 手动模式，需要自行调用show 、hide 方法
   */
  props: {
    // 主题风格
    theme: {
      type: String,
      default: 'light',
      validator(val) {
        return ['light', 'dark'].includes(val)
      }
    },
    // 数据 [{icon, label, info, disabled, divider, children}]
    data: {
      type: Array,
      default() {
        return []
      }
    },
    disabled: Boolean,
    zIndex: {
      type: Number,
      default: 1000
    },
    target: {
      type: [String, HTMLElement, Function],
      default() {
        return document.body
      }
    },
    // 手动控制菜单显示
    manual: Boolean,
    appendToBody: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      visible: false,
      x: 0,
      y: 0,
      rect: null
    }
  },
  computed: {
    styles() {
      return {
        left: `${this.x}px`,
        top: `${this.y}px`,
        zIndex: this.zIndex
      }
    },
    classes() {
      return {
        [`is-${this.theme}`]: !!this.theme
      }
    }
  },
  methods: {
    getTarget() {
      let el = document.body
      if (typeof this.target === 'string') {
        el = document.querySelector(this.target)
      }
      if (typeof this.target === 'function') {
        el = this.target()
      }
      return el
    },
    handleContextMenu(e) {
      if (this.disabled) return
      e.preventDefault()
      if(!this.manual) {
        this.show({x: e.pageX, y: e.pageY})
      }
      return false
    },
    getPlacement(rect, x, y) {
      const targetRect = this.triggerTarget.getBoundingClientRect()
      if (rect.height + y - Math.abs(targetRect.top) >= targetRect.height) {
        y -= rect.height
      }
      if (rect.width + x - Math.abs(targetRect.left) >= targetRect.width) {
        x -= rect.width
      }
      return {
        x, y
      }
    },
    show({x, y}) {
      console.info('show')
      this.visible = true
      this.$nextTick(() => {
        const rect = this.$refs.menu.rect
        const placement = this.getPlacement(rect, x, y)
        this.x = placement.x
        this.y = placement.y
      })
    },
    hide() {
      console.info('hide')
      this.visible = false
    }
  },
  mounted() {
    this.triggerTarget = this.getTarget()
    on(this.triggerTarget, 'contextmenu', this.handleContextMenu)
    on(document.body, 'click', this.hide)
    if(this.appendToBody) {
      document.body.appendChild(this.$el)
    }

  },
  beforeDestroy() {
    off(this.triggerTarget, 'contextmenu', this.handleContextMenu)
    off(document.body, 'click', this.hide)
    if (this.$el && this.$el.parentNode) {
      this.$el.parentNode.removeChild(this.$el)
    }
    this.triggerTarget = null
  }
}
</script>

<style lang="scss" >
.my-contextmenu {
  position: absolute;
  z-index: 1000;
  font-size: 14px;
  left: 0;
  top: 0;

  &__menu {
    display: block;
    -webkit-box-shadow: 0 2px 4px rgb(0 0 0 / 12%), 0 0 6px rgb(0 0 0 / 4%);
    box-shadow: 0 2px 4px rgb(0 0 0 / 12%), 0 0 6px rgb(0 0 0 / 4%);
    list-style: none;
    margin: 0;
    padding: 4px 0;
    min-width: 100px;
    border-radius: 2px;
    background: #fff;
  }

  &__item {
    position: relative;
    padding: 0 8px;
    height: 30px;
    line-height: 30px;
    cursor: pointer;
    clear: both;
    color: rgba(0,0,0,.85);
    display: flex;
    flex-wrap: nowrap;
    justify-content: space-between;

    &:hover {
      background: #1890ff;
      color: #e6f7ff;
    }
  }

  &__divider {
    height: 0;
    border-top: 1px solid rgba(0,0,0,.09);
    margin: 2px 0;
    clear: both;
  }

  &__icon {
    width: 20px;
    display: inline-block;
    vertical-align: top;
  }

  &__label {
    margin-right: 20px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-block;
    vertical-align: top;
  }
}

</style>
